home *** CD-ROM | disk | FTP | other *** search
/ Gekikoh Dennoh Club 1 / Gekikoh Dennoh Club Vol. 1 (Japan).7z / Gekikoh Dennoh Club Vol. 1 (Japan) (Track 1).bin / kowin / archive / sys / kowin14d.lzh / doc / programming / kowin_p5.doc < prev    next >
Text File  |  1995-09-15  |  15KB  |  494 lines

  1.  
  2. Ko-Window プログラミング、入門編 その3 「便利なライブラリ」
  3.  
  4.  
  5.  
  6.   ここではリアルタイム処理や、ボタンやポップアップメニューなど、便利なライブ
  7. ラリを使ったアプリケーションを作っていきます。
  8.  
  9.  
  10. ● EventInterval
  11.  
  12.   まず、多分誰もが知りたがっているであろうリアルタイム処理について説明します。
  13. ようするに、ユーザーが何もしなくても勝手に動いている時計などの作り方です。
  14.  
  15.   以下はサンプルプログラムです。マウスカーソルの座標を監視し、ウィンドウ内に
  16. 報告します。左側の座標が画面全体に対する絶対位置で、右の座標が現在マウスカー
  17. ソルが載っているウィンドウローカルの座標になります。
  18.  
  19. ----------------------------------------------------------------------------
  20. #include    <corlib.h>
  21.  
  22. /* 0.05秒に1回座標をチェックし表示を更新する */
  23. #define        WAIT        5
  24.  
  25. int    WindowHeapSize= 0;
  26. char    msbuf[30];
  27.  
  28. /* 描画バッファを設定する */
  29. DrawSetMouse( dp )
  30. DrawBuf    *dp;
  31. {
  32.     DrawSetSymbol( dp, 4, 4, msbuf, AttrDefault, 12 );
  33.     return    1;    /* 使用した DrawBuf 数 */
  34. }
  35.  
  36. /* マウス座標を求めて、表示文字列に変換する */
  37. MouseSetPosition( info )
  38. EventInfo    *info;
  39. {
  40.     static    Old_x, Old_y;
  41.  
  42.     /* イベント情報を新たにバッファに獲得する */
  43.     WindowGetEventInfo( info );
  44.  
  45.     /* 前と座標が同じなら何もしない */
  46.     if( info->x != Old_x || info->y != Old_y ){
  47.         int    x, y, x2= 0, y2= 0;
  48.  
  49.         Old_x= x= info->x;
  50.         Old_y= y= info->y;
  51.  
  52.         /* チャイルドウィンドウ内の座標に変換する */
  53.         if( WindowGetChild( WindowRootID, info ) )
  54.             x2= info->x, y2= info->y;
  55.  
  56.         /* 得たマウスカーソル座標を文字列に変換する */
  57.         sprintf( msbuf, "(%4d,%4d) (%4d,%4d)", x, y, x2, y2 );
  58.         return    TRUE;
  59.     }
  60.     return    FALSE;
  61. }
  62.  
  63. EventExec( wp, info )
  64. WindowID    wp;
  65. EventInfo    *info;
  66. {
  67.     DrawBuf    dbuf[10], *dp= dbuf;
  68.     static unsigned    Time;    /* 時間カウントワーク */
  69.  
  70.     switch( info->option ){
  71.     case EventOpen:
  72.         MouseSetPosition( info );
  73.         WindowRedraw( wp );
  74.         /* EventInterval を有効にする */
  75.         WindowSetEventAttr( wp, EventAttrDefault|EventIntervalON );
  76.         return    TRUE;
  77.     case EventClose:
  78.         WindowClose( wp );
  79.         WindowConnectionClose();
  80.         return    TRUE;
  81.     case EventRedraw:
  82.         DrawSetClear( dp++, ColorGray );
  83.         dp+= DrawSetMouse( dp );
  84.         WindowDraw( wp, dbuf, dp-dbuf );
  85.         return    TRUE;
  86.  
  87.     case EventInterval:    /* インターバルイベント */
  88.         if( IntervalWait( WAIT, &Time ) ){
  89.             if( MouseSetPosition( info ) )
  90.                 WindowDraw( wp, dbuf, DrawSetMouse( dp ) );
  91.             return    TRUE;
  92.         }
  93.         return    FALSE;
  94.     }
  95.     return    FALSE;
  96. }
  97.  
  98. WindowMain( argc, argv )
  99. char    **argv;
  100. {
  101.     int    x= 10, y= 10;
  102.     AnalyzeArgs( argc, argv, &x, &y, NULL, NULL );
  103.     WindowTitleOpen( x, y, 200, 20, NULL, "smpl", Close|Push, EventExec );
  104. }
  105. ----------------------------------------------------------------------------
  106.   CPU が暇な間、常に発生し続けるのがこの EventInterval です。もちろん、あま
  107. りに頻繁に発生し続けられても困るので、適度な間隔をあけて自分の処理をしなけれ
  108. ばなりません。(例えば時計なら、書き換えは1秒に1回で十分でしょう)
  109.   その処理を行っているのがこの部分です。
  110.  
  111.     if( IntervalWait( WAIT, &Time ) ){
  112.         if( MouseSetPosition( info, TRUE ) )
  113.             WindowDraw( wp, dbuf, DrawSetMouse( dp ) );
  114.         return    TRUE;
  115.     }
  116.  
  117.  IntervalWait() という関数は、指定時間以上経過すると一度だけ TRUE を返します。
  118. 時間は 1/100 秒単位なので、この例では 0.05 秒待っていることになります。&Time
  119. というのは IntervalWait() 内部で使う時間計測のためのカウンタです。適当な変数
  120. (必ず static か global) のアドレスを与えておいて下さい。
  121.  
  122.  
  123.  
  124. ●ポップアップメニュー
  125.  
  126.   ポップアップメニューは、parts.a(またはlibparts.a) の PopUpMenu() という関
  127. 数で、簡単に処理することができます。
  128.  
  129.   このサンプルでは、マウスボタンのポップアップメニューで、ウィンドウ内に表示
  130. している文字の大きさを変えることができます。
  131. ----------------------------------------------------------------------------
  132. #include    <corlib.h>
  133.  
  134. int    WindowHeapSize= 0;
  135. int    Font= 16;        /* 表示フォントサイズ */
  136.  
  137. /* メニュー文字列 */
  138. char    *menu[]= {
  139.         "10dot フォント",
  140.         "12dot フォント",
  141.         "16dot フォント",
  142.         "24dot フォント",
  143. };
  144. int    fontlist[]= { 10, 12, 16, 24 };
  145.  
  146. redraw( wp )
  147. WindowID    wp;
  148. {
  149.     DrawBuf    dbuf[10], *dp= dbuf;
  150.     DrawSetClear( dp++, ColorGray );
  151.     DrawSetSymbol( dp++, 0, 0, "サンプル", AttrDefault, Font );
  152.     WindowDraw( wp, dbuf, dp-dbuf );
  153. }
  154.  
  155. /* ポップアップメニューの処理 */
  156. popupmenu( wp, info )
  157. WindowID    wp;
  158. EventInfo    *info;
  159. {
  160.     int    n, px, py;
  161.  
  162.     /* マウスカーソルのグローバル座標を得る */
  163.     /* まずウィンドウの HOME 位置の絶対座標を得る */
  164.     WindowGetScreenPosition( wp, &px, &py );
  165.     px+= info->x;    /* それにマウスカーソル位置のローカル座標を加える */
  166.     py+= info->y;
  167.  
  168.     /* ポップアップメニュー*/
  169.     n= PopUpMenu( px-1, py, menu, sizeof menu/sizeof(char*), Font );
  170.     if( n >= 0 && n <= 3 ){
  171.         Font= fontlist[ n ];
  172.         redraw( wp );
  173.     }
  174. }
  175.  
  176. EventExec( wp, info )
  177. WindowID    wp;
  178. EventInfo    *info;
  179. {
  180.     switch( info->option ){
  181.     case EventOpen:
  182.         WindowRedraw( wp );
  183.         return    TRUE;
  184.     case EventClose:
  185.         WindowClose( wp );
  186.         WindowConnectionClose();
  187.         return    TRUE;
  188.     case EventRedraw:
  189.         redraw( wp );
  190.         return    TRUE;
  191.     case EventMouseSwitch:
  192.         if( info->LeftON || info->RightON ){
  193.             popupmenu( wp, info );
  194.             return    TRUE;
  195.         }
  196.     }
  197.     return    FALSE;
  198. }
  199.  
  200. WindowMain( argc, argv )
  201. char    **argv;
  202. {
  203.     int    x= 10, y= 10;
  204.     AnalyzeArgs( argc, argv, &x, &y, NULL, NULL );
  205.     WindowTitleOpen( x, y, 200, 50, NULL, "smpl", Close|Push, EventExec );
  206. }
  207. ----------------------------------------------------------------------------
  208.  
  209. メニュー処理を行っているのは、popupmenu() 内の PopUpMenu() です。
  210.  
  211.     PopUpMenu( x, y, メニュー文字列, 項目数, フォントサイズ );
  212.  
  213.  x, y はメニューを表示する座標で、これはルートウィンドウに対する座標(グローバ
  214. ル座標)でなければなりません。しかし、EventMouseSwitch 時に info->x, info->y
  215. で与えられる値は、すでにローカル座標に変換されてしまっています。
  216.  
  217. そこで、まずローカル座標をグローバルに変換しなければなりません。
  218.  
  219.     WindowGetScreenPosition( wp, &px, &py );
  220.  
  221. これは、それぞれのウィンドウ内の HOME 位置が、グローバル座標でどの位置に当た
  222. るかを返します。その HOME 位置の座標に、先程のローカル座標 info->x, info->y
  223. を加えてやればいいのです。
  224.  
  225. メニュー文字列は char ** で与えます。これは最初に menu[] というポインタ配列
  226. で定義しています。メニューの項目数は、menu[] がポインタ配列だということを利
  227. 用して、コンパイラに計算させています。
  228.  
  229.     sizeof menu / sizeof(char*)
  230.  
  231. これが項目数に相当します。このように記述しておけば、menu[] を書き換えるだけ
  232. で簡単に内容の増減ができるというわけです。
  233.  
  234.   さて PopUpMenu() の戻り値ですが、これはメニューのどれかが選ばれた場合、項
  235. 目番号(各項目の上から順に 0~と振った番号)が返ってきます。つまり 0~項目数 -1
  236. の範囲になるわけです。どれも選択されなかった場合は -1 が返ります。
  237.  
  238.  
  239.  
  240. ●プッシュボタン
  241.  
  242.   プッシュボタンを作るには、まずボタンの形を描画して、EventMouseSwitch 発生時
  243. に、マウスカーソルがどのボタンの上にあるか座標比較して求めなければなりません。
  244. 多くのアプリケーションは、この方法でウィンドウ内のマウス操作を行っています。
  245.  
  246.   この処理はかなり面倒になるので、それらを一手に引き受けてくれる便利なライブ
  247. ラリが存在します。MgButton ライブラリです。これは corlib.a に含まれています。
  248.  
  249. ----------------------------------------------------------------------------
  250. #include    <corlib.h>
  251.  
  252. int    WindowHeapSize= 1024*2;    /* MgButton ライブラリは HEAP を使う! */
  253. int    Attr= AttrDefault;
  254.  
  255. redraw( dp )
  256. DrawBuf    *dp;
  257. {
  258.     DrawSetSymbol( dp, 0, 0, "サンプル", Attr, 24 );
  259.     return    1;
  260. }
  261.  
  262. EventExec( wp, info )
  263. WindowID    wp;
  264. EventInfo    *info;
  265. {
  266.     DrawBuf    dbuf[30], *dp= dbuf;
  267.     static MgButton    mb;    /* MgButton で使う構造体 */
  268.     switch( info->option ){
  269.     case EventOpen:
  270.         MgButtonInit( &mb );    /* MgButton 初期化 */
  271.         /* ボタン定義 */
  272.         MgButtonSetSymbol( &mb, 4,34, 4, 1, " 灰色 ", AttrDefault,12 );
  273.         MgButtonSetSymbol( &mb,54,34, 4, 3, "  白  ", AttrDefault,12 );
  274.         MgButtonSetSymbol( &mb, 4,60, 4, 9, "灰反転", AttrDefault,12 );
  275.         MgButtonSetSymbol( &mb,54,60, 4,11, "白反転", AttrDefault,12 );
  276.         WindowRedraw( wp );
  277.         return    TRUE;
  278.     case EventClose:
  279.         WindowClose( wp );
  280.         WindowConnectionClose();
  281.         return    TRUE;
  282.     case EventRedraw:
  283.         DrawSetClear( dp++, ColorGray );
  284.         dp+= redraw( dp );
  285.         /* ボタン表示 */
  286.         WindowDraw( wp, dbuf, MgButtonSetDraw( &mb, dp ) + dp-dbuf );
  287.         return    TRUE;
  288.     case EventMouseSwitch:
  289.         if( info->LeftON ){
  290.             int    a;
  291.             /* ボタン操作 */
  292.             if( a= MgButtonOperation( wp, info, &mb ) ){
  293.                 Attr= a;
  294.                 WindowDraw( wp, dbuf, redraw( dbuf ) );
  295.             }
  296.             return    TRUE;
  297.         }
  298.     }
  299.     return    FALSE;
  300. }
  301.  
  302. WindowMain( argc, argv )
  303. char    **argv;
  304. {
  305.     int    x= 10, y= 10;
  306.     AnalyzeArgs( argc, argv, &x, &y, NULL, NULL );
  307.     WindowTitleOpen( x, y, 200,100, NULL, "smpl", Close|Push, EventExec );
  308. }
  309. ----------------------------------------------------------------------------
  310.   先程のポップアップメニューと似たようなプログラムを、プッシュボタンで作って
  311. みました。今回は大きさじゃなくて、色の変更を行っています。
  312.  
  313.   まず、この MgButton ライブラリは HEAP を使うので(内部で malloc() している)、
  314.  WindowHeapSize の設定を忘れないで下さい。
  315.  
  316.   MgButton ライブラリは、MgButton という構造体で管理されています。プログラム
  317. では MgButton mb; と宣言しています。これは必ず global か static にしてメモリ
  318. に割り付けて下さい。
  319.  
  320.   最初に MgButtonInit( &mb ); で初期化したのち、それぞれボタンを定義していき
  321. ます。ここでは EventOpen 時に MgButtonSetSymbol() を使っています。これは四角
  322. いボタンで、内部に任意の文字を書き込むことができます。
  323.  
  324.   MgButtonSetSymbol( &mb, x, y, 枠幅, ボタンナンバー, 文字列, attr, font );
  325.  
  326.  x, y はボタンを置く座標です。ボタンの大きさは、この場合文字列の文字数とフォ
  327. ントサイズで決まります。枠幅というのは、文字列から枠の四角までどれだけ間を開
  328. けるか、を示しています。ボタンナンバーというのは、そのボタンが押された時に返
  329. される値です。EventMouseSwitch の時に、この値によってどのボタンが押されたの
  330. かを判断するわけです。
  331.  
  332.   この MgButtonSetSymbol() 以外にも、Sheet(絵)で書いたボタンや、トグルボタン
  333. など、さまざま定義することができます。
  334.  
  335.     MgButtonSetDraw( &mb, DrawBuf )
  336.  
  337. これは各ボタンの描画設定をする関数です。戻り値は消費した DrawBuf の数です。
  338.  EventRedraw 時に使います。
  339.  
  340.     MgButtonOperation( &mb, info, wp )
  341.  
  342. これは、EventMouseSwitch 時に、どのボタンが押されたのかを調べるために使いま
  343. す。もしどれかのボタンが押されていれば、そのボタンのボタンナンバーを返し、ど
  344. れもおされてなければ FALSE を返します。
  345.  
  346. このサンプルプログラムでは、ボタンナンバーに直接必要な値である文字アトリビュー
  347. ト(数値)を設定してしまい、戻り値をそのまま使うという方法を取っています。
  348.  
  349.  
  350.  
  351. ●文字列の入力
  352.  
  353.   文字列の入力は、MgInput ライブラリを使うとたいへん簡単でかつ便利です。この
  354. ライブラリは corlib.a (または libcor.a) に含まれています。
  355.  
  356. ----------------------------------------------------------------------------
  357. #include    <corlib.h>
  358.  
  359. int    WindowHeapSize= 0;
  360.  
  361. EventExec( wp, info )
  362. WindowID    wp;
  363. EventInfo    *info;
  364. {
  365.     DrawBuf    dbuf[1];
  366.     static MgInput    mp;
  367.     switch( info->option ){
  368.     case EventOpen:
  369.         WindowSetEventAttr( wp, EventAttrDefault|EventUserON );
  370.         /* 入力エリアをオープン */
  371.         MgInputScrollOpen( &mp, 10, 10, wp, 30, AttrDefault, 10 );
  372.         WindowRedraw( wp );
  373.         return    TRUE;
  374.     case EventClose:
  375.         WindowClose( wp );
  376.         WindowConnectionClose();
  377.         return    TRUE;
  378.     case EventRedraw:
  379.         DrawSetClear( dbuf, ColorGray );
  380.         WindowDraw( wp, dbuf, 1 );
  381.         /* 入力エリアの描画 */
  382.         MgInputRedraw( &mp );
  383.         return    TRUE;
  384.     case EventKey:
  385.         /* 改行の入力で中身をクリアするだけ */
  386.         if( info->KeyCode == '\r' ){
  387.             MgInputClear( &mp );
  388.             return    TRUE;
  389.         }
  390.     case EventMouseSwitch:
  391.     case EventMouseEnter:
  392.     case EventMouseOut:    /*これ1つでまとめて処理してくれる*/
  393.         return    MgInputSendEvent( &mp, info );
  394.     case EventUser:        /* Paste は全部キー入力として受け取る */
  395.         return    ClipGetKeyboardAll( wp, info );
  396.     }
  397.     return    FALSE;
  398. }
  399.  
  400. WindowMain()
  401. {
  402.     WindowTitleOpen( 10, 10, 200, 80, NULL, "mg", Push|Close, EventExec );
  403. }
  404. ----------------------------------------------------------------------------
  405.   このプログラムは、単純に1行入力を行うだけのプログラムです。残念ながら文字
  406. 列を入力しても何も起こりません。ただ、この入力には行編集が可能で、ED.X 風キー
  407. 操作、または Emacs 風キー操作の双方でコントロールできます。デフォルトは ED.X
  408. キーバインドですが、あらかじめ環境変数 KOWINKEY に "iemacs" と書いておけばデ
  409. フォルトで Emacs キーバインドになります。また入力中に、[CTRL]+[_] [e] と入力
  410. しても Emacs モードになります。
  411.  
  412.   この関数は表示エリアが小さくても、キー入力に応じて内容をスクロールさせ、長
  413. い文字列入力を可能にしています。ここではスクロールバーつき関数を使っています
  414. が、スクロールバーがじゃまな場合はスクロールバーなしの入力関数を使うこともで
  415. きます。
  416.  
  417.  
  418.  
  419. ●低レベルな文字列の入力
  420.  
  421.   MgInput() を使えば行入力は極めて簡単ですが、parts.a(libparts.a) を使った
  422. 入力ルーチンもおまけで例としてあげておきます。MgInput() は比較的新しいライブ
  423. ラリなので、昔のプログラムでは全部この方法で記述されていました。参考用にどう
  424. ぞ。行編集機能は MgInput() と同じですが、エリア内のスクロールはしません。
  425.  
  426. ----------------------------------------------------------------------------
  427. #include    <corlib.h>
  428.  
  429. int    WindowHeapSize= 0;
  430. char    buffer[30];        /* キー入力した文字列が入る */
  431.  
  432. EventExec( wp, info )
  433. WindowID    wp;
  434. EventInfo    *info;
  435. {
  436.     DrawBuf    dbuf[30], *dp= dbuf;
  437.     static InputClass    input;    /* Input 関数で使う構造体 */
  438.     switch( info->option ){
  439.     case EventOpen:
  440.         /* 文字列入力位置の座標と、書き込むバッファ等を定義する */
  441.         InputSet( &input, 4, 10, buffer, 20, AttrDefault, 12 );
  442.         *buffer= '\0';
  443.         WindowRedraw( wp );
  444.         return    TRUE;
  445.     case EventClose:
  446.         WindowClose( wp );
  447.         WindowConnectionClose();
  448.         return    TRUE;
  449.     case EventRedraw:
  450.         DrawSetClear( dp++, ColorGray );
  451.         WindowDraw( wp, dbuf, InputSetDraw( dp, &input )+1 );
  452.         return    TRUE;
  453.     /* キー入力処理 */
  454.     case EventKey:
  455.         if( info->KeyCode == '\r' ){    /* RETURN キーが押された場合*/
  456.             /* 取り敢えず、入力行をクリアするだけ */
  457.             info->KeyCode= 'u' & 0x1f;    /* CTRL-U */
  458.         }
  459.         WindowDraw( wp, dbuf,
  460.             InputKey( dbuf, &input, info->KeyCode, info->ShiftStat ) );
  461.         return    TRUE;
  462.     /* マウスがウィンドウに出入りした時に、カーソルが ON/OFF して
  463.        ウィンドウのフォーカスがわかるようにする処理 */
  464.     case EventMouseEnter:
  465.     case EventMouseOut:
  466.         WindowDraw( wp, dbuf,
  467.             InputSetCursorVisible( dbuf, &input,
  468.                 info->option == EventMouseEnter ) );
  469.         return    TRUE;
  470.     }
  471.     return    FALSE;
  472. }
  473.  
  474. WindowMain( argc, argv )
  475. char    **argv;
  476. {
  477.     int    x= 10, y= 10;
  478.     AnalyzeArgs( argc, argv, &x, &y, NULL, NULL );
  479.     WindowTitleOpen( x, y, 200,50, NULL, "smpl", Close|Push, EventExec );
  480. }
  481. ----------------------------------------------------------------------------
  482.  
  483.  
  484.  
  485.  
  486. --
  487. 1994 9/04  最初に作成
  488. 1995 9/15  ライブラリの追加で内容が古くなった部分をバッサリ入れ替え
  489.  
  490. 小笠原博之
  491. oga@dgw.yz.yamagata-u.ac.jp
  492. DenDenNET: DEN0006 COR.
  493.  
  494.